package com.xy.server.service;

import com.alibaba.fastjson.JSON;
import com.github.sarxos.webcam.*;
import com.xy.server.database.FaceDBService;
import com.xy.server.database.FaceMapper;
import com.xy.server.entity.Profile;
import com.xy.server.util.ImageUtil;
import com.xy.server.util.ServerUtil;
import com.xy.server.util.TimeUtil;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service("faceService")
public class FaceService implements WebcamMotionListener {

    //3 meter
    public static final float profileRate1 = 4;
    //2 meter
    public static final float profileRate2 = 17;


    @Autowired
    private MosaicService mosaicService;

    private List<Webcam> webcamList = Webcam.getWebcams();

    private Webcam webcam;

    private Map<String,Integer> statMap = new HashMap<String,Integer>();

    public Map<String, Integer> getStatMap() {
        return statMap;
    }

    public void setStatMap(Map<String, Integer> statMap) {
        this.statMap = statMap;
    }

    private String ResPath;

    private static int times  = 0;

    private static long lastCaptureTime = System.currentTimeMillis();
    @Autowired
    private FaceMapper faceMapper;

    public void init(String resPath) throws SQLException{
        ResPath = resPath;

        String dic = faceMapper.getDicValueByName("surprise");

        statMap.put("surprise", Integer.valueOf(faceMapper.getDicValueByName("surprise")));
        statMap.put("happiness", Integer.valueOf(faceMapper.getDicValueByName("happiness")));
        statMap.put("neutral", Integer.valueOf(faceMapper.getDicValueByName("neutral")));
        statMap.put("sadness", Integer.valueOf(faceMapper.getDicValueByName("sadness")));
        statMap.put("disgust", Integer.valueOf(faceMapper.getDicValueByName("disgust")));
        statMap.put("anger", Integer.valueOf(faceMapper.getDicValueByName("anger")));
        statMap.put("fear",Integer.valueOf(faceMapper.getDicValueByName("fear")));

        for(int i = 0 ;i < webcamList.size() ; ++i){
            if(webcamList.get(i).getName().contains("C920")){
                webcam = webcamList.get(i);
            }
        }
        if(webcam == null){
            for(int i = 0 ;i < webcamList.size() ; ++i){
                if(webcamList.get(i).getName().contains("HP")){
                    webcam = webcamList.get(i);
                }if(webcamList.get(i).getName().contains("FaceTime")){
                    webcam = webcamList.get(i);
                }
            }
        }

        Dimension[] nonStandardResolutions = new Dimension[] {
                WebcamResolution.PAL.getSize(),
                WebcamResolution.HD720.getSize(),
                new Dimension(1920, 1080) };
        webcam.setCustomViewSizes(nonStandardResolutions);
        webcam.setViewSize( new Dimension(1920, 1080)); // set size
        webcam.open();

        WebcamMotionDetector detector = new WebcamMotionDetector(webcam);
        detector.setInterval(5000); // one check per 5000 ms
        detector.addMotionListener(this);
        detector.start();

    }

    @Override
    public void motionDetected(WebcamMotionEvent wme) {
        System.out.println("Detected motion I, alarm turn on you have");
        lastCaptureTime = System.currentTimeMillis();
    }

    public HashMap<?,?> capture() throws IOException{
        long nowTime = System.currentTimeMillis();
        System.out.println("(nowTime - lastCaptureTime)/1000  " + (nowTime - lastCaptureTime)/1000 );
        if((nowTime - lastCaptureTime)/1000 > 30){
            System.out.println("image not change for 30 seconds,don't request face++ any more");
            return null;
        }

        String originFileName = TimeUtil.convertToStringFormat(new Date())+".jpg";
        String photo = ResPath + originFileName;

        ImageIO.write(webcam.getImage(), "jpg", new File(photo));

        String compressFileName = originFileName.substring(0,originFileName.lastIndexOf("."));
        compressFileName += "_compress";
        String ext = originFileName.substring(originFileName.lastIndexOf("."));
        compressFileName += ext;

        //图片尺寸不变，压缩图片文件大小outputQuality实现,参数1为最高质量
        Thumbnails.of(ResPath + originFileName).scale(1f).outputQuality(0.25f).toFile(ResPath + compressFileName);

        File file = new File(ResPath + compressFileName);

        BufferedImage photoBuffered = ImageIO.read(file);
        int fullWidth = photoBuffered.getWidth();
        int fullHeight = photoBuffered.getHeight();
        int photoSize = fullWidth*fullHeight;
        int maxProfileSize  = 0;

        byte[] buff = HttpService.getBytesFromFile(file);
        String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
        HashMap<String, Object> map = new HashMap<String, Object>();
        HashMap<String, byte[]> byteMap = new HashMap<String, byte[]>();
        //test
//        map.put("api_key", "JozJrOo2lYLIWdedondt6cSSp1n_OlId");
//        map.put("api_secret", "P1tMKaLfvH5AOJ8TKdAzGSxiCqxUQEZJ");

        //paid
        map.put("api_key", "k5qR1Mf3FDKjXMyU8MqoS0qRQSAafG7F");
        map.put("api_secret", "gubFqsv2r9Vwf9FQij913k5NflzDP9ns");


        //map.put("return_landmark", "1");
        //map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
        map.put("return_attributes", "emotion");
        byteMap.put("image_file", buff);
        try{
            byte[] bacd = HttpService.post(url, map, byteMap);
            String str = new String(bacd);
            System.out.println(str);

            Map<String,Object> json = (Map<String,Object>) JSON.parse(str);
            json.put("origin_file_name",originFileName);

            List faces = (java.util.List<Object>)json.get("faces");

            for(int i = 0; i < faces.size(); ++i){
                Map<String,Object> face = (Map<String,Object>)faces.get(i);

                if(!face.containsKey("attributes")) {
                    continue;
                }

                Map<String,Object> attributes = (Map<String,Object>)face.get("attributes");

                Map<String,Object> emotion = (Map<String,Object>)attributes.get("emotion");

                String expression = getExpression(emotion);

                face.put("expression",expression);

                Map<String,Object> rectangle = (Map<String,Object>)face.get("face_rectangle");

                int top = Integer.valueOf(rectangle.get("top").toString())-20;
                int left = Integer.valueOf(rectangle.get("left").toString())-20;
                int width = Integer.valueOf(rectangle.get("width").toString())+20;
                int height = Integer.valueOf(rectangle.get("height").toString())+20;

                if(width*height > maxProfileSize){
                    maxProfileSize = width*height;
                }

                if(top < 0) {
                    top = 0;
                }
                if(left < 0) {
                    left = 0;
                }

                String profileFilename = new ImageUtil().cutImage(photo,ResPath, left,top,  width, width);

                String rotateFilename = ImageUtil.rotatePhoto(ResPath ,profileFilename,270);

                face.put("face_photo",rotateFilename);
                face.put("profile_filename",profileFilename);

                System.out.println(JSON.toJSONString(face));

            }


            float rate = maxProfileSize*1.0f/photoSize*1000;
            System.out.println("rate : " + rate);

            if(rate < profileRate1 ) {
                json.put("rate_level",1);//self video
            }else if(rate < profileRate2) {
                json.put("rate_level",2);//hello video
            }else{
                json.put("rate_level",3);//emotion video
            }

//            switch(times % 6){
//                case 0 :json.put("rate_level",1);break;//self video
//                case 1 :json.put("rate_level",2);break;//self video
//                case 2 :json.put("rate_level",3);break;//self video
//                case 3 :json.put("rate_level",3);break;//self video
//                case 4 :json.put("rate_level",3);break;//self video
//                case 5 :json.put("rate_level",1);break;//self video
//
//                default:
//                    json.put("rate_level",1);
//            }
//            times += 1;

            map.put("result", json);
            map.put("stat",statMap);

        }catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }

    public String getExpression(Map<String,Object> emotion ){
        float maxExpression = 0;
        String expression = "";
        if(Float.valueOf(emotion.get("surprise").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("surprise").toString());
            expression = "surprise";
        }
        if(Float.valueOf(emotion.get("happiness").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("happiness").toString());
            expression = "happiness";
        }
        if(Float.valueOf(emotion.get("neutral").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("neutral").toString());
            expression = "neutral";
        }
        if(Float.valueOf(emotion.get("sadness").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("sadness").toString());
            expression = "sadness";
        }
        if(Float.valueOf(emotion.get("disgust").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("disgust").toString());
            expression = "disgust";
        }
        if(Float.valueOf(emotion.get("anger").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("anger").toString());
            expression = "anger";
        }
        if(Float.valueOf(emotion.get("fear").toString()) > maxExpression){
            maxExpression = Float.valueOf(emotion.get("fear").toString());
            expression = "fear";
        }
        return expression;
    }
}
